#include "app_buffer.h"

typedef struct
{
    char *ptr;    // 数据指针
    int capacity; // 容量
    int len;      // 已经存储数据的长度
} sub_buffer_t;

typedef struct
{
    sub_buffer_t *sub_buffers[2]; // 存储读写缓冲区的地址
    int read_index;
    int write_index;

    // 防止竞态问题, 提供两个锁: 读锁 写锁
    pthread_mutex_t read_lock;
    pthread_mutex_t write_lock;
} buffer_t;

sub_buffer_t *app_buffer_init_sub_buffer(int capacity)
{
    sub_buffer_t *sub_buffer = (sub_buffer_t *)malloc(sizeof(sub_buffer_t));
    if (sub_buffer == NULL)
    {
        log_error("malloc sub_buffer error");
        return NULL;
    }

    sub_buffer->ptr = (char *)malloc(capacity);
    sub_buffer->capacity = capacity;
    sub_buffer->len = 0;

    memset(sub_buffer->ptr, 0, capacity);
    return sub_buffer;
}

buffer_handle_t app_buffer_init(int capacity)
{
    buffer_t *buffer = (buffer_t *)malloc(sizeof(buffer_t));
    if (buffer == NULL)
    {
        log_error("malloc buffer error");
        return NULL;
    }

    buffer->sub_buffers[0] = app_buffer_init_sub_buffer(capacity);
    if (buffer->sub_buffers[0] == NULL)
    {
        log_error("malloc sub_buffer error");
        free(buffer);
        return NULL;
    }

    buffer->sub_buffers[1] = app_buffer_init_sub_buffer(capacity);
    if (buffer->sub_buffers[1] == NULL)
    {
        log_error("malloc sub_buffer error");
        free(buffer->sub_buffers[0]);
        free(buffer);
        return NULL;
    }

    buffer->read_index = 0;
    buffer->write_index = 1;

    pthread_mutex_init(&buffer->read_lock, NULL);
    pthread_mutex_init(&buffer->write_lock, NULL);

    log_info("双缓冲初始 success");

    return (buffer_handle_t)buffer;
}

void app_buffer_deinit(buffer_handle_t buffer_handle)
{
    buffer_t *buffer = (buffer_t *)buffer_handle;
    pthread_mutex_destroy(&buffer->read_lock);
    pthread_mutex_destroy(&buffer->write_lock);
    free(buffer->sub_buffers[0]->ptr);
    free(buffer->sub_buffers[0]);

    free(buffer->sub_buffers[1]->ptr);
    free(buffer->sub_buffers[1]);

    free(buffer);
}

/**
 * @brief 向缓冲区写数据
 *
 * @param buffer
 * @param data
 * @param len 写入的数据的长度, 范围[1,255]
 */
gate_state_t app_buffer_write(buffer_handle_t buffer_handle, char *data, uint8_t len)
{
    buffer_t *buffer = (buffer_t *)buffer_handle;

    // 先拿到写锁
    pthread_mutex_lock(&buffer->write_lock);
    // 先找到写缓冲区
    sub_buffer_t *w_buffer = buffer->sub_buffers[buffer->write_index];

    // 开始写数据
    // 0. 先判断空间是否够
    if (w_buffer->capacity - w_buffer->len < len + 1)
    {
        log_warn("buffer is not enough: 剩余 %d byte, 需要 %d byte",
                 w_buffer->capacity - w_buffer->len,
                 len + 1);
        pthread_mutex_unlock(&buffer->write_lock);
        return GATE_ERROR;
    }

    // 1. 先写长度
    w_buffer->ptr[w_buffer->len] = len;
    // 2. 再写真正的数据
    memcpy(w_buffer->ptr + w_buffer->len + 1, data, len);

    // 3. 更新下已经写入的数据的长度
    w_buffer->len += len + 1;
    // 最后解锁
    pthread_mutex_unlock(&buffer->write_lock);

    log_info("缓冲区写入成功....");
    return GATE_OK;
}

/**
 * @brief
 *
 * @param buffer
 * @param data
 * @param data_capacity  缓冲区容量
 * @return int 读取到数据的实际长度
 */
int app_buffer_read(buffer_handle_t buffer_handle, char data[], int data_capacity)
{
    buffer_t *buffer = (buffer_t *)buffer_handle;
    pthread_mutex_lock(&buffer->read_lock);
    // 找到负责读的那个缓冲区
    sub_buffer_t *r_buffer = buffer->sub_buffers[buffer->read_index];
    if (r_buffer->len == 0)
    {
        // 没有数据可读, 交换缓冲区
        // 获取写锁
        pthread_mutex_lock(&buffer->write_lock);
        //log_info("交换缓冲区...");
        int tmp = buffer->write_index;
        buffer->write_index = buffer->read_index;
        buffer->read_index = tmp;
        // 释放写锁
        pthread_mutex_unlock(&buffer->write_lock);

        r_buffer = buffer->sub_buffers[buffer->read_index];
        if (r_buffer->len == 0)
        {
            //log_info("缓冲区空....");
            pthread_mutex_unlock(&buffer->read_lock);
            return 0;
        }
    }

    // 开始读取数据
    // 1. 先读取长度
    char len = r_buffer->ptr[0];
    if (len > data_capacity)
    {
        log_error("你提供的缓冲区容量: %d, 实际数据长度: %d, 提供的缓冲区空间不足", data_capacity, len);
        pthread_mutex_unlock(&buffer->read_lock);
        return 0;
    }
    // 2. 开始读取真正的数据
    memcpy(data, r_buffer->ptr + 1, len);

    // 3. 后面的数据,向前移动 len + 1 个字节
    memmove(r_buffer->ptr, r_buffer->ptr + 1 + len, r_buffer->capacity - 1 - len);

    // 4. 剩余的数据的长度更新
    r_buffer->len -= len + 1;

    pthread_mutex_unlock(&buffer->read_lock);
    log_info("缓冲区读取成功....");

    return len;
}
